本篇文章同步發表在 HKT 線上教室 部落格,線上影音教學課程已上架至 Udemy 和 Youtube 頻道。另外,想追蹤更多相關技術資訊,歡迎到 臉書粉絲專頁 按讚追蹤喔~
範例名稱:Google Map 顯示目前位置
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載
範例名稱:清除標記
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載
範例名稱:目前所在位置,使用預設藍色小點呈現
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載
在之前的介紹當中,我們陸陸續續學會「如何獲取位置權限」、「如何檢查GPS是否開啟」、「如何獲取目前所在位置經緯度」和「 Google Map 基本使用方式」,綜合以上幾個單元的學習,今天,我們已經可以輕鬆做出,在 Google Map 上標示並顯示目前裝置所在位置的 APP 應用程式。
將昨天介紹的範例,部分區域變數,拉出來變為全域變數
private var googleMap: GoogleMap? = null
private lateinit var mFusedLocationProviderClient: FusedLocationProviderClient
原本 getLocationPermission 寫在 onCreate ,我們將他搬到 onMapReady,代表等地圖準備好,我們再去檢查與獲取權限與位置邏輯。
override fun onMapReady(googleMap: GoogleMap) {
this.googleMap = googleMap
getLocationPermission()
}
在 onLocationResult 裡,將獲取到經緯度指定到 currentLocation,透過地圖的 addMarker 將所在位置標示出來,然後透過 moveCamera 將地圖畫面移動到此處。
val currentLocation =
LatLng(
locationResult.lastLocation.latitude,
locationResult.lastLocation.longitude
)
googleMap?.addMarker(
MarkerOptions().position(currentLocation).title("現在位置")
)
googleMap?.moveCamera(
CameraUpdateFactory.newLatLngZoom(
currentLocation, 15f
)
)
假設裝置位置不斷在改變,但我們沒有把舊的標記清掉,就會有很多之前位置點的標記。所以我們需要加入清除上一次標記的邏輯。
private var mCurrLocationMarker: Marker? = null
...
...
...
//清除所有標記
//googleMap?.clear()
//清除上一次位置標記
mCurrLocationMarker?.remove()
//當下位置存到一個 Marker 變數中,好讓下一次可以清除
mCurrLocationMarker =googleMap?.addMarker(
MarkerOptions().position(currentLocation).title("現在位置")
)
Markers (標記、圖釘),可以在地圖呈現一個指引圖案,吸引用戶看這裡。如圖所示:
其中 MarkerOptions 常用屬性,整理如下:
更多 Markers 設定可以參考官方文件: Markers。
設定 Markers 的 Icon 圖片需為 bitmap,這裡 KT 提供一個將向量圖片轉為 bitmap 的小程式。並擴充 Int 功能,新增轉 dp 和 px 功能。
package com.thishkt.pharmacydemo.util
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
object ImgUtil {
fun getBitmapDescriptor(
context: Context,
id: Int,
width: Int = 0,
height: Int = 0
): BitmapDescriptor? {
val vectorDrawable: Drawable? =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
context.getDrawable(id)
} else {
ContextCompat.getDrawable(context, id)
}
return if (vectorDrawable != null) {
if (width == 0) vectorDrawable.intrinsicWidth
if (height == 0) vectorDrawable.intrinsicHeight
vectorDrawable.setBounds(0, 0, width, height)
val bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
val canvas = Canvas(bm);
vectorDrawable.draw(canvas);
BitmapDescriptorFactory.fromBitmap(bm);
} else {
null
}
}
val Int.dp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
val Int.px: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
}
向量圖片取自 Android Studio 內建的 mask 向量圖,ic_baseline_masks_24.xml
<vector android:height="24dp" android:tint="#FF5722"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.5,6c-1.31,0 -2.37,1.01 -2.48,2.3C15.14,7.8 14.18,6.5 12,6.5c-2.19,0 -3.14,1.3 -5.02,1.8C6.87,7.02 5.81,6 4.5,6C3.12,6 2,7.12 2,8.5V9c0,6 3.6,7.81 6.52,7.98C9.53,17.62 10.72,18 12,18s2.47,-0.38 3.48,-1.02C18.4,16.81 22,15 22,9V8.5C22,7.12 20.88,6 19.5,6zM3.5,9V8.5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3c0,1.28 0.38,2.47 1.01,3.48C4.99,14.27 3.5,12.65 3.5,9zM20.5,9c0,3.65 -1.49,5.27 -3.01,5.98c0.64,-1.01 1.01,-2.2 1.01,-3.48v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V9zM10.69,10.48c-0.44,0.26 -0.96,0.56 -1.69,0.76V10.2c0.48,-0.17 0.84,-0.38 1.18,-0.58C10.72,9.3 11.23,9 12,9s1.27,0.3 1.8,0.62c0.34,0.2 0.71,0.42 1.2,0.59v1.04c-0.75,-0.21 -1.26,-0.51 -1.71,-0.78C12.83,10.2 12.49,10 12,10C11.51,10 11.16,10.2 10.69,10.48z"/>
</vector>
MarkerOptions 設定參數
googleMap?.addMarker(
MarkerOptions()
.position(currentLocation).title("現在位置")
.snippet("這裡可以顯示相關資訊,太過長會被截掉").icon(
getBitmapDescriptor(
mContext,
R.drawable.ic_baseline_masks_24,
60.px,
60.px
)
)
)
在 onMapReady 加入移動鏡頭到預設座標位置,這樣開啟時預設就會先看到此位置。
//台北101
private val defaultLocation = LatLng(25.0338483, 121.5645283)
...
...
...
override fun onMapReady(googleMap: GoogleMap) {
...
googleMap.moveCamera(
CameraUpdateFactory.newLatLngZoom(
defaultLocation, 6f
)
)
}
Marker 有一個 showInfoWindow 方法,即可在不用點任何標記下,預設開啟此標記的資訊視窗。
currLocationMarker?.showInfoWindow()
googleMap?.isMyLocationEnabled = true
HKT 線上教室
https://tw-hkt.blogspot.com/
Freepik
https://www.freepik.com/
Select Current Place and Show Details on a Map
https://developers.google.com/maps/documentation/android-sdk/current-place-tutorial
MapsActivityCurrentPlace.kt
https://github.com/googlemaps/android-samples/blob/bb1492036ad171443f549054c7e750dfe1a5cc64/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/src/main/java/com/example/currentplacedetailsonmap/MapsActivityCurrentPlace.kt
那今天【iThome 鐵人賽】就介紹到這邊囉~
順帶一提,KT 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,追蹤喔!也歡迎大家將這篇文章分享給更多人喔。
我們明天再見囉!!!掰掰~